package com.panfeng.xcloud.boss.provider.assets.service.exchange.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.binance.client.model.enums.CandlestickInterval;
import com.binance.client.model.market.Candlestick;
import com.huobi.api.enums.DirectionEnum;
import com.huobi.api.enums.OffsetEnum;
import com.huobi.api.exception.ApiException;
import com.huobi.api.request.trade.SwapLightningClosePositionRequest;
import com.huobi.api.request.trade.SwapOrderDetailRequest;
import com.huobi.api.request.trade.SwapOrderRequest;
import com.huobi.api.request.transfer.UsdtSwapTransferRequest;
import com.huobi.api.response.account.SwapAccountInfoResponse;
import com.huobi.api.response.account.SwapAccountPositionInfoResponse;
import com.huobi.api.response.account.SwapAccountInfoResponse;
import com.huobi.api.response.account.SwapAccountPositionInfoResponse;
import com.huobi.api.response.account.SwapPositionInfoResponse;
import com.huobi.api.response.trade.SwapLightningClosePositionResponse;
import com.huobi.api.response.trade.SwapOrderDetailResponse;
import com.huobi.api.response.trade.SwapOrderResponse;
import com.huobi.api.response.trade.SwapSwitchLeverRateResponse;
import com.huobi.api.response.transfer.UsdtSwapTransferResponse;
import com.huobi.api.service.account.AccountAPIServiceImpl;
import com.huobi.api.service.trade.TradeAPIServiceImpl;
import com.huobi.api.service.transfer.TransferApiServiceImpl;
import com.huobi.api.util.HbdmHttpClient;
import com.panfeng.xcloud.boss.provider.assets.dao.mapper.CoinListMapperExt;
import com.panfeng.xcloud.boss.provider.assets.dao.mapper.UserExchangePwdMapperExt;
import com.panfeng.xcloud.boss.provider.assets.service.exchange.IExchangeMethodService;
import com.panfeng.xcloud.boss.provider.assets.utils.OrderNoGenerate;
import com.panfeng.xcloud.boss.provider.dto.request.OperateBotReqDTO;
import com.panfeng.xcloud.boss.provider.dto.request.SendEmailReqDTO;
import com.panfeng.xcloud.boss.provider.rpc.member.UserInfoFeignApi;
import com.panfeng.xcloud.common.core.candle.CandleEntry;
import com.panfeng.xcloud.common.core.candle.MyCandleEntry;
import com.panfeng.xcloud.common.core.configuration.DataDictionaryConfig;
import com.panfeng.xcloud.common.core.constants.UrlPathConstants;
import com.panfeng.xcloud.common.core.enums.*;
import com.panfeng.xcloud.common.core.exceptions.BaseBizException;
import com.panfeng.xcloud.common.core.utils.DES3Util;
import com.panfeng.xcloud.common.core.utils.KeyContactUtil;
import com.panfeng.xcloud.common.core.utils.SignatureUtils;
import com.panfeng.xcloud.common.core.web.vo.InnerTransferVO;
import com.panfeng.xcloud.common.core.web.vo.OrderDetailResponseVO;
import com.panfeng.xcloud.common.core.web.vo.TradeResponseVO;
import com.panfeng.xcloud.dao.assets.entity.CoinList;
import com.panfeng.xcloud.dao.member.entity.UserExchangePwd;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import java.math.BigDecimal;
import java.util.*;

@Service
@Slf4j
public class HuobiMethodService implements IExchangeMethodService {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private DataDictionaryConfig dataDictionaryConfig;

    @Autowired
    private UserExchangePwdMapperExt userExchangePwdMapperExt;

    @Autowired
    private CoinListMapperExt coinListMapperExt;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private UserInfoFeignApi userInfoFeignApi;

    @Autowired
    @Qualifier(value = "notLoadBalancedRestTemplate")
    private RestTemplate restTemplate;

    @Value("${xdcloud.des3.secret-key}")
    private String secrectKey;

    /**
     * 查询账户总可用余额
     *
     * @param userId
     * @param valuationAsset
     * @return
     */
    @Override
    public BigDecimal getTotalAvaliableMoney(String userId, String valuationAsset) {
        String[] apiKeyAndSecretKey = getKeys(userId);
        String secretKey = apiKeyAndSecretKey[0];
        String apiKey = apiKeyAndSecretKey[1];
        String restHost = dataDictionaryConfig.getCodeToNameMap().get(DataDictionaryTypeEnum.huobi_rest_host.getCode());

        Map<String, Object> params = new HashMap();
        String body = HbdmHttpClient.getInstance().doGetKey(apiKey, secretKey, restHost + "/linear-swap-api/v3/linear_swap_overview_account_info", params);
        SwapAccountInfoResponse response = (SwapAccountInfoResponse) JSON.parseObject(body, SwapAccountInfoResponse.class);
        List<SwapAccountInfoResponse.DataBean> data = response.getData();
        BigDecimal totalAvaliableMoney = BigDecimal.ZERO;
        for (SwapAccountInfoResponse.DataBean datum : data) {
            if (datum.getMarginAsset().equalsIgnoreCase(CoinTypeEnum.USDT.getCode())) {
                if (datum.getMarginAvailable() != null) {
                    totalAvaliableMoney = datum.getMarginAvailable();
                    break;
                }
            }
        }
        return totalAvaliableMoney;
    }

    /**
     * 查询某交易对保证金率
     *
     * @param userId
     * @param contractCode
     * @param direction
     * @return
     */
    @Override
    public BigDecimal getRiskRate(String userId, String contractCode, String direction) {
        String[] apiKeyAndSecretKey = getKeys(userId);
        String secretKey = apiKeyAndSecretKey[0];
        String apiKey = apiKeyAndSecretKey[1];
        String restHost = dataDictionaryConfig.getCodeToNameMap().get(DataDictionaryTypeEnum.huobi_rest_host.getCode());

        Map<String, Object> params = new HashMap();
        params.put("contract_type", "swap");
        String body = HbdmHttpClient.getInstance().doPost(apiKey, secretKey, restHost + "/linear-swap-api/v1/swap_cross_position_info", params);
        SwapAccountInfoResponse response = (SwapAccountInfoResponse) JSON.parseObject(body, SwapAccountInfoResponse.class);
        List<SwapAccountInfoResponse.DataBean> data = response.getData();
        BigDecimal totalRiskRate = BigDecimal.ZERO;
        for (SwapAccountInfoResponse.DataBean datum : data) {
            if (datum.getMarginAsset().equalsIgnoreCase(CoinTypeEnum.USDT.getCode())) {
                if (datum.getRiskRate() != null) {
                    BigDecimal riskRate = BigDecimal.ONE.divide(datum.getRiskRate(), 6, BigDecimal.ROUND_DOWN);
                    totalRiskRate = totalRiskRate.add(riskRate);
                    break;
                }
            }
        }
        return totalRiskRate;
    }

    /**
     * 查询某交易对的可用仓位
     *
     * @param userId
     * @param contractCode
     * @param direction
     * @param leverRate
     * @return
     */
    @Override
    public BigDecimal getAvaliablePosition(String userId, String contractCode, String direction, Integer leverRate) {
        String[] apiKeyAndSecretKey = getKeys(userId);
        String secretKey = apiKeyAndSecretKey[0];
        String apiKey = apiKeyAndSecretKey[1];
        String restHost = dataDictionaryConfig.getCodeToNameMap().get(DataDictionaryTypeEnum.huobi_rest_host.getCode());

        Map<String, Object> params = new HashMap();
        params.put("contract_code", contractCode);
        params.put("pair", contractCode);
        params.put("contract_type", "swap");
        String body = HbdmHttpClient.getInstance().doPost(apiKey, secretKey, restHost + "/linear-swap-api/v1/swap_cross_position_info", params);
        JSONObject response = (JSONObject) JSON.parseObject(body, JSONObject.class);
        JSONArray jsonArray = response.getJSONArray("data");
        BigDecimal totalAvaliablePosition = BigDecimal.ZERO;
        for (Object o : jsonArray) {
            JSONObject obj = (JSONObject) o;
            String objDirection = obj.getString("direction");
            String objLeverRate = obj.getString("lever_rate");
            String[] pair = obj.getString("pair").split("-");
            String destinationCoin = pair[0];
            String sourceCoin = pair[1];
            if (objDirection.equalsIgnoreCase(direction) && objLeverRate.equalsIgnoreCase(String.valueOf(leverRate))) {
                CoinList coinList = coinListMapperExt.queryCoinListByDestinationCoinAndSourceCoin(ExchangeTypeEnum.HUOBI.getCode(),
                        destinationCoin, sourceCoin, CoinListStatusTypeEnum.OPEN.code, direction);
                BigDecimal contractCodeValue = coinList.getContractCodeValue();
                totalAvaliablePosition = new BigDecimal(obj.getString("volume")).multiply(contractCodeValue);
                break;
            }
        }

        return totalAvaliablePosition;
    }

    /**
     * 查询某交易对的开仓均价
     *
     * @param userId
     * @param contractCode
     * @param direction
     * @param leverRate
     * @return
     */
    @Override
    public BigDecimal getPositionAgvPrice(String userId, String contractCode, String direction, Integer leverRate) {
        String[] apiKeyAndSecretKey = getKeys(userId);
        String secretKey = apiKeyAndSecretKey[0];
        String apiKey = apiKeyAndSecretKey[1];
        String restHost = dataDictionaryConfig.getCodeToNameMap().get(DataDictionaryTypeEnum.huobi_rest_host.getCode());

        Map<String, Object> params = new HashMap();
        params.put("contract_code", contractCode);
        params.put("pair", contractCode);
        params.put("contract_type", "swap");
        String body = HbdmHttpClient.getInstance().doPost(apiKey, secretKey, restHost + "/linear-swap-api/v1/swap_cross_position_info", params);
        JSONObject response = (JSONObject) JSON.parseObject(body, JSONObject.class);
        JSONArray jsonArray = response.getJSONArray("data");
        BigDecimal positionAgvPrice = BigDecimal.ZERO;
        for (Object o : jsonArray) {
            JSONObject obj = (JSONObject) o;
            String objDirection = obj.getString("direction");
            String objLeverRate = obj.getString("lever_rate");
            if (objDirection.equalsIgnoreCase(direction) && objLeverRate.equalsIgnoreCase(String.valueOf(leverRate))) {
                positionAgvPrice = new BigDecimal(obj.getString("cost_hold"));
                break;
            }
        }

        return positionAgvPrice;
    }

    /**
     * 查询某交易对的可用余额
     *
     * @param userId
     * @param contractCode
     * @return
     */
    @Override
    public BigDecimal getAvaliableMoney(String userId, String contractCode) {
        BigDecimal totalAvaliableMoney = getTotalAvaliableMoney(userId, null);
        return totalAvaliableMoney;
    }

    /**
     * 查询某交易对的可开数
     *
     * @param userId
     * @param destinationCoin
     * @param sourceCoin
     * @param direction
     * @param leverRate
     * @return
     */
    @Override
    public BigDecimal getAvaliablePieces(String userId, String destinationCoin, String sourceCoin, String direction, Integer leverRate) {
        /*//最新成交价
        JSONObject marketPriceDepth = getMarketPriceDepth(userId, destinationCoin, sourceCoin);
        BigDecimal currentPrice = new BigDecimal(String.valueOf(((JSONArray) (marketPriceDepth.getJSONArray("asks").get(0))).get(0)));

        //该合约面值
        CoinList coinList = coinListMapperExt.queryCoinListByDestinationCoinAndSourceCoin(ExchangeTypeEnum.HUOBI.getCode(),
                destinationCoin, sourceCoin, CoinListStatusTypeEnum.OPEN.code, direction);
        BigDecimal contractCodeValue = coinList.getContractCodeValue();

        BigDecimal marginAvailable = getAvaliableMoney(userId, KeyContactUtil.getContractCode(ExchangeTypeEnum.HUOBI.getCode(),
                destinationCoin, sourceCoin));
        //可开张数
        BigDecimal piecesAvailable = ((marginAvailable.divide(currentPrice, coinList.getDecimal().intValue(), BigDecimal.ROUND_DOWN)).multiply(
                new BigDecimal(leverRate))).divide(contractCodeValue, 0, BigDecimal.ROUND_DOWN);
        return piecesAvailable;*/
        String contractCode = KeyContactUtil.getContractCode(ExchangeTypeEnum.HUOBI.getCode(), destinationCoin, sourceCoin);
        //该交易对可用余额
        BigDecimal availableMoney = getAvaliableMoney(userId, contractCode).multiply(new BigDecimal(leverRate));
        return availableMoney;
    }

    /**
     * 交易所下市价单
     *
     * @param operateBotReqDTO
     * @return
     */
    @Override
    public TradeResponseVO trade(OperateBotReqDTO operateBotReqDTO) {
        if (operateBotReqDTO.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
            throw new BaseBizException(ResponseStatusEnum.TRADER_AMOUNT_CANT_SMALL_THAN_ZERO);
        }
        TradeResponseVO tradeResponseVO = new TradeResponseVO();
        String[] apiKeyAndSecretKey = getKeys(operateBotReqDTO.getUserId());
        String secretKey = apiKeyAndSecretKey[0];
        String apiKey = apiKeyAndSecretKey[1];
        String restHost = dataDictionaryConfig.getCodeToNameMap().get(DataDictionaryTypeEnum.huobi_rest_host.getCode());
        String contractCode = KeyContactUtil.getContractCode(operateBotReqDTO.getExchangeType(), operateBotReqDTO.getDestinationCoin(), operateBotReqDTO.getSourceCoin());
        BigDecimal oldAvaliablePosition = null;
        BigDecimal newAvaliablePosition = null;
        String newClientOrderId = OrderNoGenerate.getOrderIdAddRandomByTime(null);

        Map<String, Object> params = new HashMap();
        params.put("contract_code", contractCode);
        params.put("pair", contractCode);
        params.put("contract_type", "swap");
        /*开多：买入开多(direction用buy、offset用open)
        平多：卖出平多(direction用sell、offset用close)
        开空：卖出开空(direction用sell、offset用open)
        平空：买入平空(direction用buy、offset用close)*/
        try {
            if (operateBotReqDTO.getOperateType() == OperateTypeEnum.BUY.getCode()) {
                oldAvaliablePosition = mustGetAvaliablePositionInTrade(operateBotReqDTO.getUserId(), contractCode, operateBotReqDTO.getDirection(), operateBotReqDTO.getLeverRate());
                params.put("volume", operateBotReqDTO.getAmount().longValue());
                if (operateBotReqDTO.getDirection().equalsIgnoreCase("buy")) {
                    params.put("direction", "buy");
                    params.put("offset", "open");
                } else if (operateBotReqDTO.getDirection().equalsIgnoreCase("sell")) {
                    params.put("direction", "sell");
                    params.put("offset", "open");
                }
                params.put("lever_rate", operateBotReqDTO.getLeverRate());
                params.put("order_price_type", "market");
                params.put("client_order_id", newClientOrderId);
                String body = HbdmHttpClient.getInstance().doPost(apiKey, secretKey, restHost + "/linear-swap-api/v1/swap_cross_order", params);
                JSONObject response = (JSONObject) JSON.parseObject(body, JSONObject.class);
                tradeResponseVO.setNewClientOrderId(newClientOrderId);
            }
        } catch (Exception e) {
            logger.error("双向王trade方法开仓时报错", e);
            newAvaliablePosition = mustGetAvaliablePositionInTrade(operateBotReqDTO.getUserId(), contractCode, operateBotReqDTO.getDirection(), operateBotReqDTO.getLeverRate());
            if (oldAvaliablePosition.add(operateBotReqDTO.getAmount()).compareTo(newAvaliablePosition) == 0) {
                String message = "双向王trade开仓时报错但实际交易所下单成功   用户id:" + operateBotReqDTO.getUserId()
                        + "   方向:" + operateBotReqDTO.getDirection()
                        + "   倍数:" + operateBotReqDTO.getLeverRate()
                        + "   交易对:" + contractCode
                        + "   异常信息:" + com.panfeng.xcloud.common.core.utils.StringUtils.printStackTraceToString(e);
                userInfoFeignApi.sendEmail(new SendEmailReqDTO(message));
                tradeResponseVO.setNewClientOrderId(newClientOrderId);
            } else {
                String message = "双向王trade开仓时报错实际交易所下单也失败   用户id:" + operateBotReqDTO.getUserId()
                        + "   方向:" + operateBotReqDTO.getDirection()
                        + "   倍数:" + operateBotReqDTO.getLeverRate()
                        + "   交易对:" + contractCode
                        + "   异常信息:" + com.panfeng.xcloud.common.core.utils.StringUtils.printStackTraceToString(e);
                userInfoFeignApi.sendEmail(new SendEmailReqDTO(message));
                throw e;
            }
        }

        try {
            if (operateBotReqDTO.getOperateType() == OperateTypeEnum.SELL.getCode()) {
                CoinList coinList = coinListMapperExt.queryCoinListByDestinationCoinAndSourceCoin(ExchangeTypeEnum.HUOBI.getCode(),
                        operateBotReqDTO.getDestinationCoin(), operateBotReqDTO.getSourceCoin(), CoinListStatusTypeEnum.OPEN.code, operateBotReqDTO.getDirection());
                BigDecimal contractCodeValue = coinList.getContractCodeValue();
                params.put("volume", operateBotReqDTO.getAmount().divide(contractCodeValue, 0, BigDecimal.ROUND_DOWN).longValue());
                if (operateBotReqDTO.getDirection().equalsIgnoreCase("buy")) {
                    params.put("direction", "sell");
                    params.put("offset", "close");
                } else if (operateBotReqDTO.getDirection().equalsIgnoreCase("sell")) {
                    params.put("direction", "buy");
                    params.put("offset", "close");
                }
                params.put("lever_rate", operateBotReqDTO.getLeverRate());
                params.put("order_price_type", "market");
                String body = HbdmHttpClient.getInstance().doPost(apiKey, secretKey, restHost + "/linear-swap-api/v1/swap_cross_order", params);
                JSONObject response = (JSONObject) JSON.parseObject(body, JSONObject.class);
                tradeResponseVO.setOrderId(response.getJSONObject("data").getLong("order_id"));
            }
        } catch (Exception e) {
            logger.error("双向王trade方法平仓时报错", e);
            String message = "双向王trade平仓时报错   用户id:" + operateBotReqDTO.getUserId()
                    + "   方向:" + operateBotReqDTO.getDirection()
                    + "   倍数:" + operateBotReqDTO.getLeverRate()
                    + "   交易对:" + contractCode
                    + "   异常信息:" + com.panfeng.xcloud.common.core.utils.StringUtils.printStackTraceToString(e);
            userInfoFeignApi.sendEmail(new SendEmailReqDTO(message));
            throw e;
        }

        tradeResponseVO.setCreatedAt(new Date().getTime());

        return tradeResponseVO;
    }

    /**
     * 获取订单详情
     *
     * @param operateBotReqDTO
     * @param tradeResponseVO
     * @return
     */
    @Override
    public OrderDetailResponseVO getOrderDetail(OperateBotReqDTO operateBotReqDTO, TradeResponseVO tradeResponseVO) {
        String[] apiKeyAndSecretKey = getKeys(operateBotReqDTO.getUserId());
        String secretKey = apiKeyAndSecretKey[0];
        String apiKey = apiKeyAndSecretKey[1];
        String restHost = dataDictionaryConfig.getCodeToNameMap().get(DataDictionaryTypeEnum.huobi_rest_host.getCode());
        String contractCode = KeyContactUtil.getContractCode(operateBotReqDTO.getExchangeType(), operateBotReqDTO.getDestinationCoin(), operateBotReqDTO.getSourceCoin());

        Map<String, Object> params = new HashMap();
        params.put("contract_code", contractCode);
        params.put("pair", contractCode);
        params.put("created_at", tradeResponseVO.getCreatedAt());
        JSONObject data = null;
        while (data == null) {
            try {
                //获取订单详情
                if (tradeResponseVO.getOrderId() == null || tradeResponseVO.getOrderId() == 0l) {
                    params.put("client_order_id", tradeResponseVO.getNewClientOrderId());
                    String body = HbdmHttpClient.getInstance().doPost(apiKey, secretKey, restHost + "/linear-swap-api/v1/swap_cross_order_info", params);
                    JSONObject response = (JSONObject) JSON.parseObject(body, JSONObject.class);
                    data = (JSONObject) response.getJSONArray("data").get(0);
                } else {
                    params.put("order_id", tradeResponseVO.getOrderId());
                    String body = HbdmHttpClient.getInstance().doPost(apiKey, secretKey, restHost + "/linear-swap-api/v1/swap_cross_order_info", params);
                    JSONObject response = (JSONObject) JSON.parseObject(body, JSONObject.class);
                    data = (JSONObject) response.getJSONArray("data").get(0);
                }
            } catch (Exception e) {
                logger.error("双向王getOrderDetail方法疯狂循环中", e);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
            }
        }

        CoinList coinList = coinListMapperExt.queryCoinListByDestinationCoinAndSourceCoin(ExchangeTypeEnum.HUOBI.getCode(),
                operateBotReqDTO.getDestinationCoin(), operateBotReqDTO.getSourceCoin(), CoinListStatusTypeEnum.OPEN.code, operateBotReqDTO.getDirection());
        BigDecimal contractCodeValue = coinList.getContractCodeValue();
        OrderDetailResponseVO orderDetailResponseVO = new OrderDetailResponseVO();
        orderDetailResponseVO.setContractCode(data.getString("contract_code"));
        orderDetailResponseVO.setLeverRate(operateBotReqDTO.getLeverRate());
        orderDetailResponseVO.setDirection(operateBotReqDTO.getDirection());
        orderDetailResponseVO.setVolume(data.getBigDecimal("volume").multiply(contractCodeValue));
        orderDetailResponseVO.setVolumeNum(data.getBigDecimal("volume").multiply(contractCodeValue));
        orderDetailResponseVO.setPrice(data.getBigDecimal("trade_avg_price"));
        orderDetailResponseVO.setCreatedAt(data.getLong("created_at"));
        orderDetailResponseVO.setFeeAsset(data.getString("fee_asset"));
        orderDetailResponseVO.setOrderId(data.getLong("order_id"));
        orderDetailResponseVO.setTradeAvgPrice(data.getBigDecimal("trade_avg_price"));
        orderDetailResponseVO.setTradeTurnover(data.getBigDecimal("trade_turnover"));
        orderDetailResponseVO.setTradeVolume(data.getBigDecimal("trade_volume").multiply(contractCodeValue));
        orderDetailResponseVO.setTradeVolumeNum(data.getBigDecimal("trade_volume").multiply(contractCodeValue));
        orderDetailResponseVO.setRealProfit(data.getBigDecimal("real_profit"));
        orderDetailResponseVO.setFee(data.getBigDecimal("fee").abs());

        return orderDetailResponseVO;
    }

    /**
     * 同账户内资金划转
     *
     * @param innerTransferVO
     * @return
     */
    @Override
    public String transferInner(InnerTransferVO innerTransferVO) {
        TransferApiServiceImpl transferService = getTransferAPIService(innerTransferVO.getUserId());
        UsdtSwapTransferRequest request = UsdtSwapTransferRequest.builder()
                .from(innerTransferVO.getFrom())
                .to(innerTransferVO.getTo())
                .margin_account(innerTransferVO.getMarginAccount())
                .currency(innerTransferVO.getAsset())
                .amount(innerTransferVO.getAmount())
                .build();
        UsdtSwapTransferResponse response = transferService.transfer(request);

        return String.valueOf(response.getData());
    }

    /**
     * 获取展示市价
     *
     * @param userId
     * @param destinationCoin
     * @param sourceCoin
     * @return
     */
    @Override
    public BigDecimal getAppearMarketPrice(String userId, String destinationCoin, String sourceCoin) {
        int symbol = 0;
        while (symbol < 5) {
            try {
                String contractCode = KeyContactUtil.getContractCode(ExchangeTypeEnum.HUOBI.getCode(), destinationCoin, sourceCoin);
                String restHost = dataDictionaryConfig.getCodeToNameMap().get(DataDictionaryTypeEnum.huobi_rest_host.getCode());
                String url = restHost + UrlPathConstants.HUOBI_KLINE + "contract_code=" + contractCode + "&period=1min&size=1";
                ResponseEntity<String> result = restTemplate.getForEntity(url, String.class);
                JSONArray array = (JSONObject.parseObject(result.getBody())).getJSONArray("data");
                if (array.size() == 0) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException interruptedException) {
                        interruptedException.printStackTrace();
                    }
                    continue;
                }
                JSONObject data = (JSONObject) array.get(0);
                String closePrice = data.getString("close");
                redisTemplate.opsForValue().set(KeyContactUtil.getAppearMarketKey(ExchangeTypeEnum.HUOBI.getCode(), destinationCoin, sourceCoin), closePrice);
                return new BigDecimal(closePrice);
            } catch (ApiException e) {
                symbol++;
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException interruptedException) {
                    interruptedException.printStackTrace();
                }
            }
        }
        throw new BaseBizException(ResponseStatusEnum.GET_APPERPRICE_ERROR);
    }

    /**
     * 获取行情深度,供计算使用
     *
     * @param userId
     * @param destinationCoin
     * @param sourceCoin
     * @return
     */
    @Override
    public JSONObject getMarketPriceDepth(String userId, String destinationCoin, String sourceCoin) {
        String restHost = dataDictionaryConfig.getCodeToNameMap().get(DataDictionaryTypeEnum.huobi_rest_host.getCode());
        String contractCode = KeyContactUtil.getContractCode(ExchangeTypeEnum.HUOBI.getCode(), destinationCoin, sourceCoin);
        String url = restHost + UrlPathConstants.HUOBI_DEPTH_MARKET_PRICE + contractCode;
        ResponseEntity<String> result = restTemplate.getForEntity(url, String.class);
        JSONObject data = JSONObject.parseObject(result.getBody());
        if (data.getString("status").equals("ok")) {
            JSONObject depth = data.getJSONObject("tick");
            return depth;
        } else {
            throw new BaseBizException(ResponseStatusEnum.MARKET_PRICE_REQUEST_ERROR);
        }
    }

    /**
     * 判断杠杆倍数是否可用
     *
     * @param userId
     * @param destinationCoin
     * @param sourceCoin
     * @param leverRate
     * @return
     */
    @Override
    public boolean leverRateCanUse(String userId, String destinationCoin, String sourceCoin, Integer leverRate) {
        String[] split = {
                "1", "2", "3", "4", "5", "6", "7", "8", "9",
                "10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
                "20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
                "30", "31", "32", "33", "34", "35", "36", "37", "38", "39",
                "40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
                "50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
                "60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
                "70", "71", "72", "73", "74", "75", "100", "125"};
        return Arrays.asList(split).contains(String.valueOf(leverRate));
    }

    /**
     * 调用接口调整杠杆倍数
     *
     * @param userId
     * @param destinationCoin
     * @param sourceCoin
     * @param leverRate
     * @return
     */
    @Override
    public boolean changeLeverRate(String userId, String destinationCoin, String sourceCoin, Integer leverRate) {
        String contractCode = KeyContactUtil.getContractCode(ExchangeTypeEnum.HUOBI.getCode(), destinationCoin, sourceCoin);
        TradeAPIServiceImpl tradeService = getTradeAPIService(userId);
        SwapSwitchLeverRateResponse swapSwitchLeverRate = tradeService.getSwapSwitchLeverRate(contractCode, leverRate);
        String status = swapSwitchLeverRate.getStatus();
        if (status.equals("ok")) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 获取K线数据
     *
     * @param exchangeType
     * @param userId
     * @param destinationCoin
     * @param sourceCoin
     * @param interval
     * @param startTime
     * @param endTime
     * @param limit
     * @return
     */
    public JSONObject getCandleStick(Integer exchangeType, String userId, String destinationCoin, String sourceCoin, CandlestickInterval interval, Long startTime, Long endTime, int limit) {
        String contractCode = KeyContactUtil.getContractCode(ExchangeTypeEnum.HUOBI.getCode(), destinationCoin, sourceCoin);
        String restHost = dataDictionaryConfig.getCodeToNameMap().get(DataDictionaryTypeEnum.huobi_rest_host.getCode());
        String period = "1min";
        long duration = 0l;
        switch (interval.toString()) {
            case "1m":
                period = "1min";
                duration = 60;
                break;
            case "5m":
                period = "5min";
                duration = 300;
                break;
            case "15m":
                period = "15min";
                duration = 900;
                break;
            case "30m":
                period = "30min";
                duration = 1800;
                break;
            case "1h":
                period = "60min";
                duration = 3600;
                break;
            case "4h":
                period = "4hour";
                duration = 14400;
                break;
            case "1d":
                period = "1day";
                duration = 86400;
                break;
            case "1w":
                period = "1week";
                duration = 604800;
                break;
            case "1M":
                period = "1mon";
                duration = 2592000;
                break;
            default:
                period = "1mon";
                duration = 2592000;
                break;
        }
        String url = restHost + UrlPathConstants.HUOBI_KLINE + "contract_code=" + contractCode + "&period=" + period + "&size=" + limit;

        if (startTime != null) {
            url = url.concat("&from=" + startTime);
        }

        if (endTime != null) {
            url = url.concat("&to=" + endTime);
        }

        JSONArray reqData = restTemplate.getForObject(url, JSONObject.class).getJSONArray("data");
        List<Candlestick> candles = packCandles(reqData,duration);
        List<CandleEntry> entries = new ArrayList<>();
        for (int i = 0; i < candles.size(); i++) {
            Candlestick candlestick = candles.get(i);
            entries.add(new MyCandleEntry(i, candlestick.getHigh().floatValue(), candlestick.getLow().floatValue(), candlestick.getOpen().floatValue(), candlestick.getClose().floatValue(), candlestick.getVolume().floatValue(), candlestick.getOpenTime(), candlestick.getCloseTime(), candlestick.getQuoteAssetVolume()));
        }
        JSONArray result = JSONArray.parseArray(JSONArray.toJSONString(entries));
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("candlesticks", result);

        return jsonObject;
    }

    //---------------------------------------------------------------------分隔符-------------------------------------------------------------------------------------
    private AccountAPIServiceImpl getAccountAPIService(String userId) {
        String[] apiKeyAndSecretKey = getKeys(userId);
        String secretKey = apiKeyAndSecretKey[0];
        String apiKey = apiKeyAndSecretKey[1];
        String restHost = dataDictionaryConfig.getCodeToNameMap().get(DataDictionaryTypeEnum.huobi_rest_host.getCode());
        AccountAPIServiceImpl accountService = new AccountAPIServiceImpl(apiKey, secretKey, restHost);
        return accountService;
    }

    private TradeAPIServiceImpl getTradeAPIService(String userId) {
        String[] apiKeyAndSecretKey = getKeys(userId);
        String secretKey = apiKeyAndSecretKey[0];
        String apiKey = apiKeyAndSecretKey[1];
        String restHost = dataDictionaryConfig.getCodeToNameMap().get(DataDictionaryTypeEnum.huobi_rest_host.getCode());
        TradeAPIServiceImpl tradeService = new TradeAPIServiceImpl(apiKey, secretKey, restHost);
        return tradeService;
    }

    private TransferApiServiceImpl getTransferAPIService(String userId) {
        String[] apiKeyAndSecretKey = getKeys(userId);
        String secretKey = apiKeyAndSecretKey[0];
        String apiKey = apiKeyAndSecretKey[1];
        String restHost = dataDictionaryConfig.getCodeToNameMap().get(DataDictionaryTypeEnum.huobi_auth_host.getCode());
        TransferApiServiceImpl transferService = new TransferApiServiceImpl(apiKey, secretKey, restHost);
        return transferService;
    }

    private String[] getKeys(String userId) {
        String[] keys = {"", ""};
        List<UserExchangePwd> userExchangePwd = userExchangePwdMapperExt.queryByUserId(userId, ExchangeTypeEnum.HUOBI.getCode());

        if (userExchangePwd.size() != 2)
            throw new BaseBizException(ResponseStatusEnum.QUAN_BOT_HUO_BI_API_KEY_NOT_BIND);

        //API KEY 解密
        for (UserExchangePwd userExchangePwdAsset : userExchangePwd) {
            if (userExchangePwdAsset.getExchangeType().equals(ExchangeTypeEnum.HUOBI.getCode())) {
                String salt = userExchangePwdAsset.getSalt();
                Integer pwdType = userExchangePwdAsset.getPwdType();
                String pwd = userExchangePwdAsset.getPwd();
                String decode = DES3Util.doubleDecode(pwd, secrectKey, salt);
                if (ExchangePwdTypeEnum.secretKey.code == pwdType) {
                    keys[0] = decode;
                } else if (ExchangePwdTypeEnum.apiKey.code == pwdType) {
                    keys[1] = decode;
                }
            }
        }
        return keys;
    }

    private List<Candlestick> packCandles(JSONArray reqData, Long duration) {
        List<Candlestick> result = new LinkedList();
        for (Object reqDatum : reqData) {
            Candlestick element = new Candlestick();
            JSONObject data = (JSONObject) reqDatum;

            Long openTime = data.getLong("id");
            Long closeTime = openTime + duration;
            element.setOpenTime(openTime);
            element.setHigh(new BigDecimal(data.getString("high")));
            element.setLow(new BigDecimal(data.getString("low")));
            element.setOpen(new BigDecimal(data.getString("open")));
            element.setClose(new BigDecimal(data.getString("close")));
            element.setVolume(new BigDecimal(data.getString("amount")));
            element.setCloseTime(closeTime);
            element.setQuoteAssetVolume(new BigDecimal(data.getString("trade_turnover")));
            result.add(element);
        }
        return result;
    }

    private BigDecimal mustGetAvaliablePositionInTrade(String userId, String contractCode, String direction, Integer leverRate) {
        BigDecimal avaliablePosition = null;
        while (avaliablePosition == null) {
            try {
                avaliablePosition = getAvaliablePosition(userId, contractCode, direction, leverRate);
            } catch (Exception e) {
                logger.error("双向王trade方法中获取仓位时报错", e);
                String message = "双向王trade方法中获取仓位时报错  用户id:" + userId
                        + "   方向:" + direction
                        + "   倍数:" + leverRate
                        + "   交易对:" + contractCode
                        + "   异常信息:" + com.panfeng.xcloud.common.core.utils.StringUtils.printStackTraceToString(e);
                userInfoFeignApi.sendEmail(new SendEmailReqDTO(message));
            }
        }
        return avaliablePosition;
    }

}
